#ifndef SYSTEMMONITOR_H
#define SYSTEMMONITOR_H

#include "source/logger.h"
#include "cameraeth0.h"
#include <QObject>
#include <QMap>
#include <QQueue>
#include <QTimer>
#include <QThread>
#include <functional>

struct CpuData {
    QString name;
    quint64 user;
    quint64 nice;
    quint64 system;
    quint64 idle;
    quint64 iowait;
    quint64 irq;
    quint64 softirq;
    quint64 steal;
    quint64 guest;
    quint64 guest_nice;

    quint64 totalTime() const {
        return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
    }

    quint64 activeTime() const {
        return user + nice + system + irq + softirq + steal;
    }
};

class Worker : public QObject {
    Q_OBJECT

public slots:
    void processTask(std::function<void()> task) {
        task();
    }
};

class CameraWorker : public QObject {
    Q_OBJECT
public slots:
    void monitorParameters() {
        if(CameraEth0::getInstance().getIsOpened())
            CameraEth0::getInstance().monitorParameters();
    }
};

class SystemMonitor : public QObject {
    Q_OBJECT

    Q_PROPERTY(float cpuUsage READ cpuUsage NOTIFY cpuUsageChanged)
    Q_PROPERTY(QVariantMap cpuUsageMap READ cpuUsageMap NOTIFY cpuUsageChanged)
    Q_PROPERTY(float memoryUsage READ memoryUsage NOTIFY memoryUsageChanged)
    Q_PROPERTY(float temperature READ temperature NOTIFY temperatureChanged)
    Q_PROPERTY(QString threadPoolUsage READ threadPoolUsage NOTIFY threadPoolUsageChanged)
    Q_PROPERTY(QString currentTime READ currentTime NOTIFY currentTimeChanged)
    Q_PROPERTY(float diskUsage READ diskUsage NOTIFY diskUsageChanged)
    Q_PROPERTY(float networkUpload READ networkUpload NOTIFY networkUploadChanged)
    Q_PROPERTY(float networkDownload READ networkDownload NOTIFY networkDownloadChanged)
    Q_PROPERTY(float gpuUsage READ gpuUsage NOTIFY gpuUsageChanged)
    Q_PROPERTY(float gpuTemperature READ gpuTemperature NOTIFY gpuTemperatureChanged)
    Q_PROPERTY(QString systemUptime READ systemUptime NOTIFY systemUptimeChanged)
    Q_PROPERTY(QString batteryStatus READ batteryStatus NOTIFY batteryStatusChanged)


public:
    explicit SystemMonitor(QObject *parent = nullptr);
    ~SystemMonitor();
    void setRefreshInterval(const QString &metric, int interval);

    float cpuUsage() const { return m_cpuUsage; }
    QVariantMap cpuUsageMap() const {return m_cpuUsageMap;}
    float memoryUsage() const { return m_memoryUsage; }
    float temperature() const { return m_temperature; }
    QString threadPoolUsage() const { return m_threadPoolUsage; }
    QString currentTime() const { return m_currentTime; }
    float diskUsage() const { return m_diskUsage; }
    float networkUpload() const { return m_networkUpload; }
    float networkDownload() const { return m_networkDownload; }
    float gpuUsage() const { return m_gpuUsage; }
    float gpuTemperature() const { return m_gpuTemperature; }
    QString systemUptime() const { return m_systemUptime; }
    QString batteryStatus() const { return m_batteryStatus; }

signals:
    void processCameraTask();
    void scheduleNextTask();
    void processTask(std::function<void()> task);

    void cpuUsageChanged();
    void memoryUsageChanged();
    void temperatureChanged();
    void threadPoolUsageChanged();
    void currentTimeChanged();
    void diskUsageChanged();
    void networkUploadChanged();
    void networkDownloadChanged();
    void gpuUsageChanged();
    void gpuTemperatureChanged();
    void systemUptimeChanged();
    void batteryStatusChanged();

public slots:
    void scheduleMetricsUpdate();
    void processNextTask();


private:
    QThread m_cameraWorkerThread;
    CameraWorker m_cameraWorker;

    void initializeTimer();

    struct Metric {
        int interval;
        qint64 lastUpdateTime;
        std::function<void()> fetchFunction;
    };

    QMap<QString, CpuData> m_previousCpuData;

    QThread m_workerThread;
    Worker m_worker;
    QTimer m_timer;
    QQueue<std::function<void()>> m_taskQueue;
    QMap<QString, Metric> m_metrics;
    float m_cpuUsage;
    float m_memoryUsage;
    float m_temperature;
    QString m_threadPoolUsage;
    QString m_currentTime;
    float m_diskUsage;
    float m_networkUpload;
    float m_networkDownload;
    float m_gpuUsage;
    float m_gpuTemperature;
    QString m_systemUptime;
    QString m_batteryStatus;
    QVariantMap m_cpuUsageMap;

    void fetchCpuUsage();
    void fetchMemoryUsage();
    void fetchTemperature();
    void fetchThreadPoolUsage();
    void fetchCurrentTime();
    void fetchDiskUsage();
    void fetchNetworkUsage();
    void fetchGpuUsage();
    void fetchSystemUptime();
    void fetchBatteryStatus();
    void fetchTotalCpuUsage();
    void fetchPerCoreCpuUsage();
};

#endif // SYSTEMMONITOR_H
